/******************************************************************************
 * Copyright (c) 2022 Telink Semiconductor (Shanghai) Co., Ltd. ("TELINK")
 * All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 *****************************************************************************/
#include "emi.h"
#include "stimer.h"
/**********************************************************************************************************************
 *                                           local macro                                                             *
 *********************************************************************************************************************/
#define EMI_STATE0         0x1234
#define EMI_STATE1         0x5678
#define EMI_TX_FIFO_ADDR   0x14081c
#define EMI_TX_PKT_PAYLOAD 37

/**********************************************************************************************************************
 *                                           global constants                                                        *
 *********************************************************************************************************************/

static unsigned char emi_rx_packet[128] __attribute__((aligned(4)));
static unsigned char emi_ble_tx_packet[48] __attribute__((aligned(4))) = {3, 0, 0, 0, 0, 10};
static unsigned char emi_zigbee_tx_packet[48] __attribute__((aligned(4))) = {19, 0, 0, 0, 20, 0, 0};
static unsigned int s_emi_rx_cnt __attribute__((aligned(4))) = 0;
static unsigned int s_emi_rssibuf = 0;
static signed char s_emi_rssi = 0;
static unsigned int s_state0, s_state1;

/**********************************************************************************************************************
 *                                          function implementation                                                   *
 *********************************************************************************************************************/

/**
 * @brief      This function serves to set singletone power
 * @param[in]  level - the power level.
 * @return     none
 */
void rf_set_power_level_index_singletone(rf_power_level_e level)
{
    unsigned char value = 0;

    if (level & BIT(7)) {
        write_reg8(0x140e3c, (read_reg8(0x140e3c) & 0xbf) | ((0x01) << 6));  // VANT
    } else {
        write_reg8(0x140e3c, (read_reg8(0x140e3c) & 0xbf));
    }
    reg_rf_ll_ctrl0 = 0x55;  // tx_en
    delay_us(150);

    value = (unsigned char)level & 0x3f;
    write_reg8(0x140f78, read_reg8(0x140f78) | BIT(6));                 // TX_PA_PWR_OW  BIT6 set 1
    write_reg8(0x140f7c, (read_reg8(0x140f7c) & 0x81) | (value << 1));  // TX_PA_PWR  BIT1 t0 BIT6 set value
}

extern unsigned char g_single_tong_freqoffset;

/**
 * @brief      This function serves to set the TX singletone power and channel
 * @param[in]  power_level - the power level.
 * @param[in]  rf_chn      - the channel.
 * @return     none
 */
void rf_emi_tx_single_tone(rf_power_level_e power_level, signed char rf_chn)
{
    g_single_tong_freqoffset = 1;
    rf_mode_init();
    rf_set_zigbee_250K_mode();
    rf_set_chn(rf_chn);
    rf_set_power_level_index_singletone(power_level);
    rf_set_txmode();
    g_single_tong_freqoffset = 0;
}

/**
 * @brief      This function serves to stop emi/(close RF)
 * @return     none
 */
void rf_emi_stop(void)
{
    write_reg8(0x140f78, 0);
    write_reg8(0x140f7c, 0);  // TX_PA_PWR
    rf_set_power_level_index(0);
    rf_set_tx_rx_off();
}

/**
 * @brief      This function serves to set the CD mode correlation register
 * @return     none
 */
void rf_emi_tx_continue_setup(void)
{
    write_reg8(0x140800, 0x0a);
    write_reg8(0x140808, 0x00);  // access code

    write_reg8(0x140801, 0x80);  // kick tx controller to wait data
    s_state0 = EMI_STATE0;
    s_state1 = EMI_STATE1;
}

/**
 * @brief      This function serves to update the CD mode data
 * @param[in]  rf_mode     - mode of RF.
 * @param[in]  power_level - power level of RF.
 * @param[in]  rf_chn      - channel of RF.
 * @param[in]  pkt_type    - The type of data sent.
 * -#0:random
 * -#1:0xf0
 * -#2:0x55
 * @return     none
 */
void rf_emi_tx_continue_update_data(rf_mode_e rf_mode, rf_power_level_e power_level, signed char rf_chn,
                                    unsigned char pkt_type)
{
    rf_mode_init();
    switch (rf_mode) {
        case RF_MODE_BLE_1M_NO_PN:
            rf_set_ble_1M_NO_PN_mode();
            break;
        case RF_MODE_BLE_2M:
            rf_set_ble_2M_NO_PN_mode();
            break;
        case RF_MODE_LR_S2_500K:
            rf_set_ble_500K_mode();
            break;
        case RF_MODE_LR_S8_125K:
            rf_set_ble_125K_mode();
            break;
        case RF_MODE_ZIGBEE_250K:
            rf_set_zigbee_250K_mode();
            break;

        default:
            break;
    }
    rf_pn_disable();
    rf_set_chn(rf_chn);
    reg_rf_ll_ctrl0 = 0x45;  // reset tx/rx state machine
    rf_set_power_level_index_singletone(power_level);
    rf_emi_tx_continue_setup();
    write_reg8(0x140808, pkt_type);  // 0:pbrs9 	1:0xf0	 2:0x55
}

/**
 * @brief      This function serves to generate random number.
 * @param[in]  state - the old random number.
 * @return     the new random number
 */
unsigned int emi_pn_gen(unsigned int state)
{
    unsigned int feed = 0;
    feed = (state & 0x4000) >> 1;
    state ^= feed;
    state <<= 1;
    state = (state & 0xfffe) + ((state & 0x8000) >> 15);
    return state;
}

/**
 * @brief      This function serves to continue to run the CD mode
 * @return     none
 */
void rf_continue_mode_run(void)
{
    if (read_reg8(0x140808) == 1) {
        write_reg32(EMI_TX_FIFO_ADDR, 0x0f0f0f0f);
    } else if (read_reg8(0x140808) == 2) {
        write_reg32(EMI_TX_FIFO_ADDR, 0x55555555);
    } else if (read_reg8(0x140808) == 3) {
        write_reg32(EMI_TX_FIFO_ADDR, read_reg32(0x140809));
    } else if (read_reg8(0x140808) == 4) {
        write_reg32(EMI_TX_FIFO_ADDR, 0);
    } else if (read_reg8(0x140808) == 5) {
        write_reg32(EMI_TX_FIFO_ADDR, 0xffffffff);
    } else {
        write_reg32(EMI_TX_FIFO_ADDR, (s_state0 << 16) + s_state1);
        s_state0 = emi_pn_gen(s_state0);
        s_state1 = emi_pn_gen(s_state1);
    }

    while (read_reg8(EMI_TX_FIFO_ADDR) & 0x1) {
    }
}

/**
 * @brief      This function serves to set rx mode and channel
 * @param[in]  mode   - mode of RF.
 * @param[in]  rf_chn - the rx channel.
 * @return     none
 */
void rf_emi_rx_setup(rf_mode_e mode, signed char rf_chn)
{
    rf_mode_init();
    switch (mode) {
        case RF_MODE_BLE_1M_NO_PN:
            rf_set_ble_1M_NO_PN_mode();
            break;
        case RF_MODE_BLE_2M:
            rf_set_ble_2M_NO_PN_mode();
            break;
        case RF_MODE_LR_S2_500K:
            rf_set_ble_500K_mode();
            break;
        case RF_MODE_LR_S8_125K:
            rf_set_ble_125K_mode();
            break;
        case RF_MODE_ZIGBEE_250K:
            rf_set_zigbee_250K_mode();
            break;

        default:
            break;
    }
    rf_set_rx_dma(emi_rx_packet, 3, 64);
    rf_pn_disable();
    rf_set_chn(rf_chn);  // set freq
    if (mode != RF_MODE_ZIGBEE_250K) {
        rf_access_code_comm(EMI_ACCESS_CODE);
    }  // accesscode
    rf_set_tx_rx_off();
    rf_set_rxmode();
    delay_us(150);
    s_emi_rssi = 0;
    s_emi_rssibuf = 0;
    s_emi_rx_cnt = 0;
}

/**
 * @brief    This function serves to update the number of receiving packet and the RSSI
 * @return   none
 */
void rf_emi_rx_loop(void)
{
    if (rf_get_irq_status(FLD_RF_IRQ_RX)) {       // rx irq
        if ((read_reg8(0x140840) & 0xf0) == 0) {  // crc err
            s_emi_rssibuf += (read_reg8(0x140c5d));
            if (s_emi_rx_cnt) {
                if (s_emi_rssibuf != 0) {
                    s_emi_rssibuf >>= 1;
                }
            }
            s_emi_rssi = s_emi_rssibuf - 110;
            s_emi_rx_cnt++;
        }
        rf_clr_irq_status(FLD_RF_IRQ_RX);  // clr rx irq
        write_reg8(0x140a00, 0x80);        // stop cmd
    }
}

/**
 * @brief    This function serves to get the number of packets received
 * @return   the number of packets received
 */
unsigned int rf_emi_get_rxpkt_cnt(void)
{
    return s_emi_rx_cnt;
}

/**
 * @brief    This function serves to get the RSSI of packets received
 * @return   the RSSI of packets received
 */
char rf_emi_get_rssi_avg(void)
{
    return s_emi_rssi;
}

/**
 * @brief      This function serves to generate random packets that need to be sent in burst mode
 * @param[in] *p - the address of random packets.
 * @param[in]  n - the number of random packets.
 * @return     none
 */
void rf_phy_test_prbs9(unsigned char *p, int n)
{
    unsigned short x = 0x1ff;
    int i = 0;
    int j = 0;
    for (i = 0; i < n; i++) {
        unsigned char d = 0;
        for (j = 0; j < 8; j++) {
            if (x & 1) {
                d |= BIT(j);
            }
            x = (x >> 1) | (((x << 4) ^ (x << 8)) & 0x100);
        }
        *p++ = d;
    }
}

/**
 * @brief      This function serves to send packets in the burst mode
 * @param[in]  rf_mode  - mode of RF.
 * @param[in]  pkt_type - The type of data sent.
 * -#0:random
 * -#1:0xf0
 * -#2:0x55
 * @return     none
 */

void rf_emi_tx_burst_loop(rf_mode_e rf_mode, unsigned char pkt_type)
{
    unsigned char rf_data_len = EMI_TX_PKT_PAYLOAD + 1;
    unsigned int rf_tx_dma_len = rf_tx_packet_dma_len(rf_data_len);
    write_reg8(0x140a00, 0x80);  // stop SM
    rf_set_txmode();
    if ((rf_mode == RF_MODE_BLE_1M_NO_PN) || (rf_mode == RF_MODE_BLE_2M)) {  // ble
        rf_data_len = EMI_TX_PKT_PAYLOAD + 2;
        rf_tx_dma_len = rf_tx_packet_dma_len(rf_data_len);
        emi_ble_tx_packet[4] = 0;
        emi_ble_tx_packet[5] = EMI_TX_PKT_PAYLOAD;
        emi_ble_tx_packet[3] = (rf_tx_dma_len >> 24) & 0xff;
        emi_ble_tx_packet[2] = (rf_tx_dma_len >> 16) & 0xff;
        emi_ble_tx_packet[1] = (rf_tx_dma_len >> 8) & 0xff;
        emi_ble_tx_packet[0] = rf_tx_dma_len & 0xff;
        rf_start_stx((void *)emi_ble_tx_packet, read_reg32(0x140200) + 10);
        while (!(rf_get_irq_status(FLD_RF_IRQ_TX))) {
        }

        rf_clr_irq_status(FLD_RF_IRQ_TX);

        delay_ms(2);
        if (pkt_type == 0) {
            rf_phy_test_prbs9(&emi_ble_tx_packet[6], 37);
        }
    } else if (rf_mode == RF_MODE_LR_S8_125K) {
        rf_data_len = EMI_TX_PKT_PAYLOAD + 2;
        rf_tx_dma_len = rf_tx_packet_dma_len(rf_data_len);
        emi_ble_tx_packet[4] = 0;
        emi_ble_tx_packet[5] = EMI_TX_PKT_PAYLOAD;
        emi_ble_tx_packet[3] = (rf_tx_dma_len >> 24) & 0xff;
        emi_ble_tx_packet[2] = (rf_tx_dma_len >> 16) & 0xff;
        emi_ble_tx_packet[1] = (rf_tx_dma_len >> 8) & 0xff;
        emi_ble_tx_packet[0] = rf_tx_dma_len & 0xff;
        rf_start_stx((void *)emi_ble_tx_packet, read_reg32(0x140200) + 10);
        while (!(rf_get_irq_status(FLD_RF_IRQ_TX))) {
        }

        rf_clr_irq_status(FLD_RF_IRQ_TX);

        delay_ms(2);
        if (pkt_type == 0) {
            rf_phy_test_prbs9(&emi_ble_tx_packet[6], 37);
        }
    } else if (rf_mode == RF_MODE_LR_S2_500K) {
        rf_data_len = EMI_TX_PKT_PAYLOAD + 2;
        rf_tx_dma_len = rf_tx_packet_dma_len(rf_data_len);
        emi_ble_tx_packet[4] = 0;
        emi_ble_tx_packet[5] = EMI_TX_PKT_PAYLOAD;
        emi_ble_tx_packet[3] = (rf_tx_dma_len >> 24) & 0xff;
        emi_ble_tx_packet[2] = (rf_tx_dma_len >> 16) & 0xff;
        emi_ble_tx_packet[1] = (rf_tx_dma_len >> 8) & 0xff;
        emi_ble_tx_packet[0] = rf_tx_dma_len & 0xff;
        rf_start_stx((void *)emi_ble_tx_packet, read_reg32(0x140200) + 10);
        while (!(rf_get_irq_status(FLD_RF_IRQ_TX))) {
        }

        rf_clr_irq_status(FLD_RF_IRQ_TX);

        delay_ms(2);
        if (pkt_type == 0) {
            rf_phy_test_prbs9(&emi_ble_tx_packet[6], 37);
        }
    } else if (rf_mode == RF_MODE_ZIGBEE_250K) {
        rf_data_len = EMI_TX_PKT_PAYLOAD + 1;
        rf_tx_dma_len = rf_tx_packet_dma_len(rf_data_len);
        emi_zigbee_tx_packet[4] = EMI_TX_PKT_PAYLOAD + 2;
        emi_zigbee_tx_packet[3] = (rf_tx_dma_len >> 24) & 0xff;
        emi_zigbee_tx_packet[2] = (rf_tx_dma_len >> 16) & 0xff;
        emi_zigbee_tx_packet[1] = (rf_tx_dma_len >> 8) & 0xff;
        emi_zigbee_tx_packet[0] = rf_tx_dma_len & 0xff;
        rf_start_stx((void *)emi_zigbee_tx_packet, read_reg32(0x140200) + 10);
        while (!(rf_get_irq_status(FLD_RF_IRQ_TX))) {
        }

        rf_clr_irq_status(FLD_RF_IRQ_TX);

        delay_us(625 * 2);
        if (pkt_type == 0) {
            rf_phy_test_prbs9(&emi_zigbee_tx_packet[5], 37);
        }
    }
}

/**
 * @brief      This function serves to set the burst mode
 * @param[in]  rf_mode     - mode of RF.
 * @param[in]  power_level - power level of RF.
 * @param[in]  rf_chn      - channel of RF.
 * @param[in]  pkt_type    - The type of data sent.
 * -#0:random
 * -#1:0xf0
 * -#2:0x55
 * @return     none
 */
void rf_emi_tx_burst_setup(rf_mode_e rf_mode, rf_power_level_e power_level, signed char rf_chn, unsigned char pkt_type)
{
    unsigned char i = 0;
    unsigned char tx_data = 0;
    write_reg8(0x10083c, 0x10);  // print buffer size set
    rf_set_tx_dma(2, 128);
    rf_set_chn(rf_chn);
    rf_mode_init();
    switch (rf_mode) {
        case RF_MODE_BLE_1M_NO_PN:
            rf_set_ble_1M_NO_PN_mode();
            break;
        case RF_MODE_BLE_2M:
            rf_set_ble_2M_NO_PN_mode();
            break;
        case RF_MODE_LR_S2_500K:
            rf_set_ble_500K_mode();
            break;
        case RF_MODE_LR_S8_125K:
            rf_set_ble_125K_mode();
            break;
        case RF_MODE_ZIGBEE_250K:
            rf_set_zigbee_250K_mode();
            break;

        default:
            break;
    }
    if (rf_mode != RF_MODE_ZIGBEE_250K) {
        rf_access_code_comm(EMI_ACCESS_CODE);  // accesscode
    }

    rf_pn_disable();
    rf_set_power_level(power_level);
    if (pkt_type == 1) {
        tx_data = 0x0f;
    } else if (pkt_type == 2) {
        tx_data = 0x55;
    }

    switch (rf_mode) {
        case RF_MODE_LR_S2_500K:
        case RF_MODE_LR_S8_125K:
        case RF_MODE_BLE_1M_NO_PN:
        case RF_MODE_BLE_2M:
            emi_ble_tx_packet[4] = pkt_type;  // type
            for (i = 0; i < 37; i++) {
                emi_ble_tx_packet[6 + i] = tx_data;
            }
            break;
        case RF_MODE_ZIGBEE_250K:
            emi_zigbee_tx_packet[5] = pkt_type;  // type
            for (i = 0; i < 37; i++) {
                emi_zigbee_tx_packet[5 + i] = tx_data;
            }
            break;

        default:
            break;
    }
}

/**
 * @brief      This function serves to reset baseband
 * @return     none
 */
void rf_emi_reset_baseband(void)
{
    reg_rst3 &= (~FLD_RST3_ZB);  // reset baseband
    reg_rst3 |= (FLD_RST3_ZB);   // clr baseband
}
